﻿#include "PixelFormatConversionTool.h"
#include "../utils/FFmpegUtils.h"

extern "C"
{
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavutil/avutil.h"
}

PixelFormatConversionTool::PixelFormatConversionTool()
{
}


bool PixelFormatConversionTool::Init(
	int src_width,
	int src_height,
	int target_width,
	int target_height,
	std::string in_filename,
	std::string out_filename,
	PIXFMT in_pix_fmt,
	PIXFMT out_pix_fmt)
{
	this->srcWidth = src_width;
	this->srcHeight = src_height;
	this->targetWidth = target_width;
	this->targetHeight = target_height;
	this->inFilename = in_filename;
	this->outFilename = out_filename;
	this->inPixFmt = in_pix_fmt;
	this->outPixFmt = out_pix_fmt;
	Close();
	reader = BinaryFileReader::Create();
	writer = BinaryFileWriter::Create();
	reader->width = this->srcWidth;
	reader->height = this->srcHeight;
	reader->filename = this->inFilename;
	reader->Init();
	writer->Init(this->outFilename);

	AVPixelFormat inFormat;
	switch (this->inPixFmt)
	{
	case RGBA:
		inFormat = AV_PIX_FMT_RGBA;
		break;
	case ARGB:
		inFormat = AV_PIX_FMT_ARGB;
		break;
	case RGB24:
		inFormat = AV_PIX_FMT_RGB24;
		break;
	case YUV420P:
		inFormat = AV_PIX_FMT_YUV420P;
		break;
	}

	AVPixelFormat outFormat;
	switch (this->outPixFmt)
	{
	case RGBA:
		outFormat = AV_PIX_FMT_RGBA;
		break;
	case ARGB:
		outFormat = AV_PIX_FMT_ARGB;
		break;
	case RGB24:
		outFormat = AV_PIX_FMT_RGB24;
		break;
	case YUV420P:
		outFormat = AV_PIX_FMT_YUV420P;
		break;
	}
	//初始化SwsContext
	sc = sws_getCachedContext(sc,
		this->srcWidth, this->srcHeight, inFormat,//输入的宽高及像素格式
		this->targetWidth, this->targetHeight,//输出的宽高
		outFormat,//输出的像素格式
		SWS_BILINEAR,//双线性插值算法
		0, 0, 0
	);
	if (!sc)
	{
		qDebug() << "sws_getCachedContext failed!";
	}
	return true;
}

bool PixelFormatConversionTool::Close()
{
	if (reader) {
		reader->Close();
		reader = nullptr;
	}
	if (writer)
	{
		writer->Close();
		writer = nullptr;
	}
	if (inData) {
		delete inData;
		inData = nullptr;
	}
	if (sc) {
		sws_freeContext(sc);
		sc = NULL;
	}
	return true;
}
/// <summary>
/// 开始转换像素格式
/// </summary>
/// <param name="in_pix_fmt"></param>
/// <param name="out_pix_fmt"></param>
/// <returns></returns>
bool PixelFormatConversionTool::Start()
{
	//输入参数配置
	int readSize = 0;
	switch (this->inPixFmt)
	{
	case YUV420P:
		readSize = this->srcWidth * this->srcHeight * 1.5;
		inData = new char[readSize];
		break;
	case RGB24:
		readSize = this->srcWidth * this->srcHeight * 3;
		inData = new char[readSize];
		break;
	case RGBA:
	case ARGB:
		readSize = this->srcWidth * this->srcHeight * 4;
		inData = new char[readSize];
		break;
	}




	while (isRunning) {
		bool ret = reader->Read(inData, readSize);
		if (!ret)
		{
			qDebug() << "读取完成";
			break;
		}

		//输入参数配置
		const uint8_t* srcData[AV_NUM_DATA_POINTERS];
		int srcLines[AV_NUM_DATA_POINTERS];
		switch (this->inPixFmt) {
		case YUV420P:
		{
			size_t y_size = this->srcWidth * this->srcHeight;
			size_t uv_size = (this->srcWidth / 2) * (this->srcHeight / 2);
			uint8_t* y_data = (uint8_t*)inData;
			uint8_t* u_data = y_data + y_size;
			uint8_t* v_data = u_data + uv_size;
			srcData[0] = y_data;
			srcData[1] = u_data;
			srcData[2] = v_data;

			srcLines[0] = this->srcWidth;
			srcLines[1] = this->srcWidth / 2;
			srcLines[2] = this->srcWidth / 2;
		}
		break;
		case RGB24:
			break;
		case RGBA:
		case ARGB:
			break;
		}


		//输出参数配置
		//
		uint8_t* targetData[AV_NUM_DATA_POINTERS];
		int targetLines[AV_NUM_DATA_POINTERS];
		uint8_t* outPixData;
		switch (this->outPixFmt) {
		case YUV420P:
		{

		}
		break;
		case RGB24:
			break;
		case RGBA:
		case ARGB:
			outPixData = new uint8_t[this->targetWidth * this->targetHeight * 4];
			targetData[0] = outPixData;
			targetLines[0] = this->targetWidth * 4;
			break;
		}
		//开始转换
		ret = sws_scale(sc
			, srcData, srcLines, 0, this->srcHeight,
			targetData, targetLines
		);

		int outSize = 0;
		switch (this->outPixFmt) {
		case YUV420P:
		{
			outSize = this->targetWidth * this->targetHeight * 1.5;
		}
		break;
		case RGB24:
			outSize = this->targetWidth * this->targetHeight * 3;
			break;
		case RGBA:
		case ARGB:
			outSize = this->targetWidth * this->targetHeight * 4;
			break;
		}
		writer->Write((char*)targetData[0], outSize);
		if (outPixData) {
			delete outPixData;
		}
	}
	return true;
}



PixelFormatConversionTool::~PixelFormatConversionTool()
{
}
